package lightswitch.server.code.gui;

import java.awt.EventQueue;
import java.awt.Point;
import java.awt.Toolkit;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;

import javax.swing.plaf.SliderUI;
import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JMenuBar;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.InputEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JTree;
import javax.swing.JPopupMenu;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import lightswitch.code.connection.ConnectionHelper;
import lightswitch.server.code.datahelper.XMLManagement;
import lightswitch.server.code.extendedcontrol.BackgroundPanel;
import lightswitch.server.code.extendedcontrol.MyComboboxEditor;
import lightswitch.server.code.extendedcontrol.MyTreeCellRenderer;
import lightswitch.server.code.model.MyTableModel;
import lightswitch.server.code.object.DataRow;
import lightswitch.server.code.object.Database;
import lightswitch.server.code.object.Property;
import lightswitch.server.code.object.Reference;
import lightswitch.server.code.object.Table;


import javax.swing.JTable;

public class MainFrame extends JFrame {
    private static JPanel contentPane;
    private JTree tree;
    protected static JTable jTable;
    protected static int lastRow = -1;
    protected static int lastCol = -1;
    public static Database currentDatabase;
    public static Boolean isShowTableData = null;
    public static Icon addIcon;
    public static Icon deleteIcon;
    public static Icon editIcon;
    public static Icon openIcon;
    public static Icon removeIcon;
    public static Icon switchIcon;
    public static Icon viewIcon;
    public static Icon aboutIcon;
    public static Icon connectIcon;

    /**
     * Launch the application.
     */
    private static boolean isAuthen = false;
    private static String path = null;
    private static JScrollPane scrollPane;
    private static JPopupMenu popupMenuForTablePane;
    private static Vector<Integer> colunmsWithComboBox;
    private static Vector<Vector<String>> values;
    public static void main(String[] args) {

        path = System.getProperty("user.dir") + "\\database.xml";
       System.out.println(path);
        XMLManagement.loadXML(path);
        String nameDatabase = null;
        Object[] databaseNames = XMLManagement.getListOfDatabaseNames();
        String s = (String) JOptionPane.showInputDialog(null, "Choose database for loading:\n", "Load database",
                JOptionPane.PLAIN_MESSAGE, null, databaseNames, "_default");
        if ("".equals(s) || s == null) {
            System.exit(1);
        } else {
            nameDatabase = s;
        }

        authenAndLoad(nameDatabase);
        initEditorCell();

        // /
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    final MainFrame frame = new MainFrame();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public static void authenAndLoad(String databaseName) {
        while (!isAuthen) {
            isAuthen = login();
        }
        loadDatabase(databaseName);
    }

    private static void loadDatabase(String databaseName) {
        currentDatabase = new Database(XMLManagement.getListOfTables(databaseName));
        currentDatabase.name = databaseName;
    }

    protected void saveDatabase() {
        if (currentDatabase.flagChangeData) {
            XMLManagement.mergeTables(Database.tables, currentDatabase.name);
            XMLManagement.saveData(path);
        }
    }

    private static boolean login() {
        // Check login
        return true;
    }

    /**
     * Create the frame.
     */
    public MainFrame() {
        setIconImage(Toolkit.getDefaultToolkit().getImage("icon.jpg"));
        setTitle("Lightswitch - SQL server");
        //Load image
        addIcon = new ImageIcon("add-icon.png");
        deleteIcon = new ImageIcon("delete-icon.png");
        editIcon = new ImageIcon("edit-icon.png");
        openIcon = new ImageIcon("open-icon.png");
        removeIcon = new ImageIcon("remove-icon.png");
        switchIcon = new ImageIcon("switch-icon.png");
        viewIcon = new ImageIcon("view-icon.png");
        aboutIcon = new ImageIcon("about-icon.png");
        connectIcon = new ImageIcon("connect-icon.png");
        
        setResizable(false);
        setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent we) {
                if (currentDatabase.flagChangeData) {
                    int result = JOptionPane.showConfirmDialog(null, "Save data in your session?",
                            "Confirm save & exit", JOptionPane.YES_NO_CANCEL_OPTION);
                    if (result == JOptionPane.YES_OPTION) {
                        saveDatabase();
                        System.exit(1);
                    } else if (result == JOptionPane.NO_OPTION) {
                        System.exit(1);
                    }
                } else {
                    int result = JOptionPane.showConfirmDialog(null, "Exit program?", "Confirm",
                            JOptionPane.OK_CANCEL_OPTION);
                    if (result == JOptionPane.OK_OPTION) {
                        System.exit(1);
                    }
                }

            }
        });

        setBounds(100, 100, 800, 400);

        JMenuBar menuBar = new JMenuBar();
        menuBar.setBounds(0, 0, 100, 25);
        setJMenuBar(menuBar);

        JMenu mnTable = new JMenu("Menu");
        menuBar.add(mnTable);
        
        JMenuItem mntmCreateNewDatabase = new JMenuItem("Create new database");
        mntmCreateNewDatabase.setIcon(addIcon);
        mntmCreateNewDatabase.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                int res = addNewDatabaseWithDialog(null, false);
                if (res == 3) {
                    // save switch to new;
                    saveDatabase();
                    loadDatabase(tempDatabase);
                    loadTreeViewAndInitListener();
                    repaint();
                }
            }
        });

        mnTable.add(mntmCreateNewDatabase);

        JMenuItem mntmSwitchDatabase = new JMenuItem("Switch database");
        mntmSwitchDatabase.setIcon(switchIcon);
        mntmSwitchDatabase.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, InputEvent.CTRL_MASK));

        mntmSwitchDatabase.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {

                if (currentDatabase.flagChangeData) {
                    int result = JOptionPane.showConfirmDialog(null, "Save data in your session?",
                            "Confirm save & exit", JOptionPane.YES_NO_CANCEL_OPTION);
                    if (result == JOptionPane.YES_OPTION) {
                        saveDatabase();
                    } else if (result == JOptionPane.CANCEL_OPTION) {
                        return;
                    }
                }

                Object[] databaseNames = XMLManagement.getListOfDatabaseNames();
                String s = (String) JOptionPane.showInputDialog(null, "Choose database for loading:\n",
                        "Switch database to", JOptionPane.PLAIN_MESSAGE, null, databaseNames, currentDatabase.getName());
                if ("".equals(s) || currentDatabase.getName().equals(s) || s == null)
                    return;

                loadDatabase(s);
                loadTreeViewAndInitListener();
                repaint();
            }
        });

        mnTable.add(mntmSwitchDatabase);

        JMenuItem mntmSetPort = new JMenuItem("Start new listener");
        mntmSetPort.setIcon(connectIcon);
       
        mntmSetPort.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                ConnectionHelper.port = showDialogGetPort(ConnectionHelper.port);
                new ConnectionThread().start();
            }
        });

        mnTable.add(mntmSetPort);

        
        JMenu mnHelp = new JMenu("Help");
        menuBar.add(mnHelp);
        
        JMenuItem mntmAbout = new JMenuItem("About");
        mntmAbout.setIcon(aboutIcon);
        mntmAbout.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseReleased(MouseEvent e) {
                // show dialog about
                JOptionPane.showMessageDialog(null, "Lightswitch server v1.0\n0912005--Trần Thị Mỹ Dung\n0912149--Phạm Thuận Hiếu",
                        "About", 1);
            }
        });
        mnHelp.add(mntmAbout);
        
        
        contentPane = new BackgroundPanel();
        ((BackgroundPanel)contentPane).setBG("bg_server.png");
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        contentPane.setLayout(null);
        setContentPane(contentPane);
        loadTreeViewAndInitListener();

    }
    protected int showDialogGetPort(int port) {
        String oldValue = String.valueOf(port);
        String invalid = "";
        JTextField tex=new JTextField(oldValue);
        while (true){
            int res = JOptionPane.showConfirmDialog(null, tex, "Set port(1..65535) " + invalid, JOptionPane.OK_CANCEL_OPTION);
            if (res!=JOptionPane.OK_OPTION)
                return port;
            
            try{
            int temp = Integer.parseInt(tex.getText());
            if (temp>0 &&temp<65536)
                return temp;
            } catch (Exception e){
            }
            invalid="again";
            oldValue = tex.getText();
        }
    }

    private void loadTreeViewAndInitListener() {
        Object[] hierarchy = getHierarchyTableName().toArray();
        DefaultMutableTreeNode root = processHierarchy(hierarchy);

        if (tree != null) {
            contentPane.remove(tree);
        }

        if (scrollPane != null) {
            contentPane.remove(scrollPane);
        }

        tree = new JTree(root);
        tree.setBounds(12, 13, 147, 317);
        tree.setCellRenderer(new MyTreeCellRenderer());
        contentPane.add(tree);

        final JPopupMenu popupMenuForDatabaseTree = initPopupMenuForDatabaseTree();

        final JPopupMenu popupMenuForTableTree = initPopupMenuForTableTree();

        tree.addMouseListener(new MouseAdapter() {
            public void mouseReleased(MouseEvent e) {
                TreePath tp = tree.getClosestPathForLocation(e.getX(), e.getY());
                if (tp != null) {
                    String temp = tp.getLastPathComponent().toString();
                    if (SwingUtilities.isLeftMouseButton(e)) {
                        if (!temp.equals(currentDatabase.getName()) && e.getClickCount() >= 2) {
                            Database.lastChosenTable = temp;
                            tree.setSelectionPath(tp);
                            initJTable(false, true);
                            repaint();
                        }
                    } else if (e.isPopupTrigger()) {
                        if (temp.equals(currentDatabase.getName())) {
                            popupMenuForDatabaseTree.show(e.getComponent(), e.getX(), e.getY());
                            return;
                        }
                        Database.lastChosenTable = temp;
                        tree.setSelectionPath(tp);
                        popupMenuForTableTree.show(e.getComponent(), e.getX(), e.getY());
                    }
                }
            }
        });

        initPopupMenuForTablePane();
    }
    private void initPopupMenuForTablePane() {
        popupMenuForTablePane = new JPopupMenu();

        JMenuItem mntmInsertRowTable = new JMenuItem("Insert new row");
        mntmInsertRowTable.setIcon(addIcon);
        mntmInsertRowTable.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (isShowTableData != null) {
                    if (isShowTableData == true) {
                        // new datarow
                        addNewDataRowToLastTable();
                    } else {
                        // new property
                        addNewPropertyToLastTable();
                    }
                    MainFrame.currentDatabase.flagChangeData = true;
                    repaint();
                }
            }
        });
        popupMenuForTablePane.add(mntmInsertRowTable);

        JMenuItem mntmDeleteRowTable = new JMenuItem("Delete this row");
        mntmDeleteRowTable.setIcon(deleteIcon);
        mntmDeleteRowTable.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                Table tb = Database.getLoadedTable(Database.lastChosenTable);
                int modelRow = jTable.convertRowIndexToModel(lastRow);
                if (isShowTableData != null && tb != null) {
                    if (isShowTableData == true) {
                        // show confirm
                        int result = JOptionPane.showConfirmDialog(null, "Delete following data row?\n"
                                + tb.getDataRow(modelRow).toString(), "Confirm", JOptionPane.OK_CANCEL_OPTION);
                        if (result == JOptionPane.OK_OPTION) {
                            // delete datarow
                            if (tb.removeDataRow(modelRow)) {
                                initJTable(false, false);
                                repaint();
                                MainFrame.currentDatabase.flagChangeData = true;
                                JOptionPane.showMessageDialog(null, "Delete data row success.", "Message", 1);
                                return;
                            }
                            JOptionPane.showMessageDialog(null, "Delete data row failed.\nCheck reference.", "Message", 1);
                        }
                    } else {
                        // show confirm
                        int result = JOptionPane.showConfirmDialog(null, "Delete following property?\n"
                                + tb.getProperty(modelRow).toString(), "Confirm", JOptionPane.OK_CANCEL_OPTION);
                        if (result == JOptionPane.OK_OPTION) {
                            // delete property
                            if (tb.removeProperty(modelRow)) {
                                initJTable(true, false);
                                repaint();
                                MainFrame.currentDatabase.flagChangeData = true;
                                JOptionPane.showMessageDialog(null, "Remove property success.", "Message", 1);
                                return;
                            }
                            JOptionPane.showMessageDialog(null, "Remove property failed.", "Message", 1);
                        }
                    }
                }
            }
        });

        popupMenuForTablePane.add(mntmDeleteRowTable);

        JMenuItem mntmEditCell = new JMenuItem("Edit this cell");
        mntmEditCell.setIcon(editIcon);
        mntmEditCell.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (lastRow < 0 || lastCol < 0)
                    return;
                jTable.editCellAt(lastRow, lastCol);
            }
        });
        popupMenuForTablePane.add(mntmEditCell);
    }

    private JPopupMenu initPopupMenuForTableTree() {
        final JPopupMenu popupMenuForTableTree = new JPopupMenu();

        JMenuItem mntmViewTable = new JMenuItem("View table");
        mntmViewTable.setIcon(viewIcon);
        mntmViewTable.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                initJTable(true, true);
                repaint();
            }
        });
        popupMenuForTableTree.add(mntmViewTable);

        JMenuItem mntmShowTableData = new JMenuItem("Show table data");
        mntmShowTableData.setIcon(viewIcon);
        mntmShowTableData.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                initJTable(false, true);
                repaint();
            }
        });
        popupMenuForTableTree.add(mntmShowTableData);

        JMenuItem mntmInsertProperty = new JMenuItem("Add property");
        mntmInsertProperty.setIcon(addIcon);
        mntmInsertProperty.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                addNewPropertyToLastTable();
            }
        });
        popupMenuForTableTree.add(mntmInsertProperty);

        JMenuItem mntmRemoveProperty = new JMenuItem("Remove property");
        mntmRemoveProperty.setIcon(removeIcon);
        mntmRemoveProperty.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                Table tb = Database.getLoadedTable(Database.lastChosenTable);
                if (tb != null) {
                    if (tb.getSizeProperties() > 0) {
                        // XXX
                        Object[] propNames = tb.getAllPropertiesName().toArray();

                        String s = (String) JOptionPane.showInputDialog(null, "Choose property for removing:\n",
                                "Remove property", JOptionPane.PLAIN_MESSAGE, null, propNames, propNames[0]);
                        if ("".equals(s) || s == null)
                            return;
                        //
                        if (tb.removeProperty(s)) {
                            initJTable(true, false);
                            MainFrame.currentDatabase.flagChangeData = true;
                            repaint();
                            JOptionPane.showMessageDialog(null, "Remove property success.", "Message", 1);

                        } else {
                            // show message
                            JOptionPane.showMessageDialog(null, "Remove property failed.", "Message", 1);
                        }
                    } else {
                        // show a message
                        JOptionPane.showMessageDialog(null,
                                "Table has no any properties.\nPlease add new property table right now.", "Message", 1);

                    }
                }
            }

        });
        popupMenuForTableTree.add(mntmRemoveProperty);

        // add reference & remove & show reference

        JMenuItem mntmShowRefs = new JMenuItem("Show all references");
        mntmShowRefs.setIcon(openIcon);
        mntmShowRefs.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                showAllRefsInLastTable();
            }
        });
        popupMenuForTableTree.add(mntmShowRefs);

        JMenuItem mntmAddRef = new JMenuItem("Add reference");
        mntmAddRef.setIcon(addIcon);
        mntmAddRef.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                addNewRefToLastTable();
            }
        });
        popupMenuForTableTree.add(mntmAddRef);

        JMenuItem mntmRemoveRef = new JMenuItem("Remove reference");
        mntmRemoveRef.setIcon(removeIcon);
        mntmRemoveRef.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                Table tb = Database.getLoadedTable(Database.lastChosenTable);
                if (tb != null) {
                    if (tb.getSizeReferences() > 0) {
                        // XXX
                        Object[] refNames = tb.getAllRefsName().toArray();

                        String s = (String) JOptionPane.showInputDialog(null, "Choose reference for removing:\n",
                                "Remove reference", JOptionPane.PLAIN_MESSAGE, null, refNames, refNames[0]);
                        if ("".equals(s) || s == null)
                            return;
                        //

                        Reference r = tb.getReference(s);

                        if (r == null) {
                            JOptionPane.showMessageDialog(null, "Remove reference failed.", "Message", 1);
                            return;
                        }

                        int result = JOptionPane.showConfirmDialog(null,
                                "Delete following reference?\n" + r.getString(), "Confirm",
                                JOptionPane.OK_CANCEL_OPTION);

                        if (result == JOptionPane.OK_OPTION) {
                            if (tb.removeReference(s)) {
                                MainFrame.currentDatabase.flagChangeData = true;
                                JOptionPane.showMessageDialog(null, "Remove reference success.", "Message", 1);
                            } else {
                                // show message
                                JOptionPane.showMessageDialog(null, "Remove reference failed.", "Message", 1);
                            }
                        }
                    } else {
                        // show a message
                        JOptionPane.showMessageDialog(null, "Table has no any references.", "Message", 1);
                    }
                }
            }

        });
        popupMenuForTableTree.add(mntmRemoveRef);
        //

        JMenuItem mntmInsertDataRow = new JMenuItem("Insert data row");
        mntmInsertDataRow.setIcon(addIcon);
        mntmInsertDataRow.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                addNewDataRowToLastTable();
                // /////
            }
        });
        popupMenuForTableTree.add(mntmInsertDataRow);

        JMenuItem mntmRemoveDataRow = new JMenuItem("Remove data row");
        mntmRemoveDataRow.setIcon(removeIcon);
        mntmRemoveDataRow.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                Table tb = Database.getLoadedTable(Database.lastChosenTable);

                if (tb.getSizeDataRows() <= 0) {
                    JOptionPane.showMessageDialog(null, "This table hasnot any data rows to remove.\n", "Message", 1);
                    return;
                } else {
                    JOptionPane.showMessageDialog(null,
                            "Please choose row in the table in the right.\nRight click -> delete this row.", "Message",
                            1);
                }
            }
        });
        popupMenuForTableTree.add(mntmRemoveDataRow);

        JMenuItem mntmDropTable = new JMenuItem("Drop table");
        mntmDropTable.setIcon(deleteIcon);
        mntmDropTable.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (Database.lastChosenTable != null) {
                    // show confirm
                    int result = JOptionPane.showConfirmDialog(null, "Drop table: " + Database.lastChosenTable,
                            "Confirm", JOptionPane.OK_CANCEL_OPTION);
                    if (result == JOptionPane.OK_OPTION) {

                        if (dropTable(Database.lastChosenTable)){
                            Database.lastChosenTable = null;
                            loadTreeViewAndInitListener();
                            MainFrame.currentDatabase.flagChangeData = true;
                            repaint();
                            return;
                        } 
                        //show dialog
                        JOptionPane.showMessageDialog(null,
                                "Cannot drop table "+Database.lastChosenTable+"\nCheck reference.", "Message", 1);
                    }
                }
            }
        });
        popupMenuForTableTree.add(mntmDropTable);
        return popupMenuForTableTree;
    }

    protected void showAllRefsInLastTable() {
        String allRefsString = currentDatabase.getAllRefsString(Database.lastChosenTable);
        if (allRefsString == null || "".equals(allRefsString)) {
            JOptionPane.showMessageDialog(null, Database.lastChosenTable + " doesn't any references to show.",
                    "All references in " + Database.lastChosenTable, 1);
            return;
        }
        JOptionPane.showMessageDialog(null, allRefsString, "All references in " + Database.lastChosenTable, 1);
    }

    protected boolean dropTable(String lastChosenTable) {
        int dropIndex = -1;
        for (int i = 0; i < currentDatabase.getSizeTables(); i++) {
            if (currentDatabase.getTable(i).getName().equals(lastChosenTable)) {
                dropIndex = i;
                break;
            }
        }
        if (dropIndex > -1) {
            if (Database.getRefToMe(lastChosenTable).size()>0)
                return false;
            
            currentDatabase.removeTable(dropIndex);
            return true;
        }

        return false;
    }

    private JPopupMenu initPopupMenuForDatabaseTree() {
        final JPopupMenu popupMenuForDatabaseTree = new JPopupMenu();

        JMenuItem mntmCreateNewTableInDatabase = new JMenuItem("Create new table");
        mntmCreateNewTableInDatabase.setIcon(addIcon);
        mntmCreateNewTableInDatabase.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                String s = JOptionPane.showInputDialog(null, "Table name: ", "Create new table", 1);

                if (s == null)
                    return;

                if ("".equals(s)) {
                    int result = JOptionPane.showConfirmDialog(null,
                            "Table name cannot null. Do you want to create again?", "Confirm",
                            JOptionPane.YES_NO_OPTION);
                    if (result == JOptionPane.YES_OPTION) {
                        actionPerformed(e);
                    }
                } else if (createNewTable(s, currentDatabase.getName())) {
                    JOptionPane.showMessageDialog(null, "Add new table success.", "Message", 1);
                    currentDatabase.flagChangeData = true;
                } else {
                    int result = JOptionPane
                            .showConfirmDialog(
                                    null,
                                    "Table name is existed. Do you want to create again?\nOr exit and change another database.",
                                    "Confirm", JOptionPane.YES_NO_OPTION);
                    if (result == JOptionPane.YES_OPTION) {
                        actionPerformed(e);
                    }
                }
            }
        });
        popupMenuForDatabaseTree.add(mntmCreateNewTableInDatabase);

        JMenuItem mntmDropTableInDatabase = new JMenuItem("Drop table");
        mntmDropTableInDatabase.setIcon(deleteIcon);
        mntmDropTableInDatabase.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                Object[] tableNames = currentDatabase.getListOfLoadedNameTables().toArray();

                if (tableNames.length == 0) {
                    JOptionPane.showMessageDialog(null,
                            "Database has no any tables.\nPlease create new table right now.", "Message", 1);
                    return;
                }

                String s = (String) JOptionPane.showInputDialog(null, "Choose table for removing:\n", "Drop table",
                        JOptionPane.PLAIN_MESSAGE, null, tableNames, Database.lastChosenTable);

                Database.lastChosenTable = s;

                if (Database.lastChosenTable != null) {

                    int result = JOptionPane.showConfirmDialog(null, "Drop table: " + Database.lastChosenTable,
                            "Confirm", JOptionPane.OK_CANCEL_OPTION);
                    if (result == JOptionPane.OK_OPTION) {
                        if(dropTable(Database.lastChosenTable)){
                            Database.lastChosenTable = null;
                            loadTreeViewAndInitListener();
                            MainFrame.currentDatabase.flagChangeData = true;
                            repaint();
                            return;
                        }
                        
                        JOptionPane.showMessageDialog(null,
                                "Cannot drop table "+Database.lastChosenTable+"\nCheck reference.", "Message", 1);
                    }
                }
            }
        });
        popupMenuForDatabaseTree.add(mntmDropTableInDatabase);

        JMenuItem mntmDropDatabase = new JMenuItem("Drop database");
        mntmDropDatabase.setIcon(deleteIcon);
        mntmDropDatabase.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if ("_default".equals(currentDatabase.getName())) {
                    JOptionPane.showMessageDialog(null,
                            "\"_default\" database cannot drop. It was created in default.", "Message", 1);
                    return;
                }

                int result = JOptionPane.showConfirmDialog(null, "Drop database: " + currentDatabase.getName(),
                        "Confirm", JOptionPane.OK_CANCEL_OPTION);
                if (result == JOptionPane.OK_OPTION) {

                    if (XMLManagement.dropDatabase(currentDatabase.getName())) {
                        JOptionPane.showMessageDialog(null, "Drop database success.", "Message", 1);
                        loadDatabase("_default");
                        loadTreeViewAndInitListener();
                        repaint();
                        return;
                    } else {
                        JOptionPane.showMessageDialog(null,
                                "This database is out of date.\nPlease refresh your database before do something.",
                                "Message", 1);
                        return;
                    }
                }
            }
        });
        popupMenuForDatabaseTree.add(mntmDropDatabase);

        return popupMenuForDatabaseTree;
    }

    protected boolean createNewTable(String tableName, String lastDatabase2) {
        if ("".equals(tableName))
            return false;
        if (isExistTable(tableName.toLowerCase(), lastDatabase2))
            return false;
        Table tb = new Table(tableName.toLowerCase(), lastDatabase2);
        currentDatabase.addTable(tb);
        loadTreeViewAndInitListener();
        Database.lastChosenTable = null;
        initJTable(true, false);
        repaint();
        return true;
    }

    private boolean isExistTable(String tableName, String lastDatabase2) {
        if ("".equals(tableName))
            return false;

        Vector<String> names = currentDatabase.getListOfLoadedNameTables();
        for (String name : names) {
            if (tableName.equals(name)) {
                return true;
            }
        }
        return false;
    }

    private DefaultMutableTreeNode processHierarchy(Object[] hierarchy) {
        DefaultMutableTreeNode node = new DefaultMutableTreeNode(hierarchy[0]);
        DefaultMutableTreeNode child;
        for (int i = 1; i < hierarchy.length; i++) {
            Object nodeSpecifier = hierarchy[i];
            if (nodeSpecifier instanceof Object[]) // Ie node with children
                child = processHierarchy((Object[]) nodeSpecifier);
            else
                child = new DefaultMutableTreeNode(nodeSpecifier); // Ie Leaf
            node.add(child);
        }
        return (node);
    }

    public static boolean initJTable(boolean isChangeView, boolean showMessage) {
        boolean changeView = isChangeView;
        if (scrollPane != null) {
            contentPane.remove(scrollPane);
        }
        Table tb = Database.getLoadedTable(Database.lastChosenTable);

        if (tb == null) {
            return false;
        } else if (tb.getSizeProperties() == 0 && changeView && showMessage) {
            JOptionPane.showMessageDialog(null, "Table has no any properties.\nPlease add new property right now.",
                    "Message", 1);
        } else if (tb.getSizeDataRows() == 0 && !changeView && showMessage) {
            JOptionPane.showMessageDialog(null, "Table is empty.\nPlease add new data row right now.", "Message", 1);
            changeView = true;
            isShowTableData = false;
        }

        MyTableModel model = null;
        if (changeView) {
            model = new MyTableModel(tb.toColumnsViewTable(), tb.toDataViewTable());
            isShowTableData = false;
        } else {
            model = new MyTableModel(tb.toColumnsShowTableData(), tb.toDataTableData());
            isShowTableData = true;
        }
        jTable = new JTable(model);
        jTable.setAutoCreateRowSorter(true);
        if (changeView) {
            int n = colunmsWithComboBox.size();
            for (int i = 0; i < n; i++) {
                int column = colunmsWithComboBox.get(i);
                TableColumn col = jTable.getColumnModel().getColumn(column);
                col.setCellEditor(new MyComboboxEditor(values.get(i)));
            }
        }

        jTable.addMouseListener(new MouseAdapter() {
            public void mouseReleased(MouseEvent e) {
                if (e.isPopupTrigger()) {
                    Point p = new Point(e.getX(), e.getY());
                    lastCol = jTable.columnAtPoint(p);
                    lastRow = jTable.rowAtPoint(p);
                    jTable.setCellSelectionEnabled(true);
                    jTable.changeSelection(lastRow, lastCol, false, false);
                    popupMenuForTablePane.show(e.getComponent(), e.getX(), e.getY());
                }
            }
        });

        scrollPane = new JScrollPane(jTable);
        if (changeView) {
            jTable.getModel().addTableModelListener(new TableModelListener() {
                public void tableChanged(TableModelEvent e) {
                    int row = e.getFirstRow();
                    int column = e.getColumn();
                    TableModel model = (TableModel) e.getSource();
                    String columnName = model.getColumnName(column);
                    Object data = model.getValueAt(row, column);
                    editTable(row, column, columnName, data, true);
                }
            });
        } else {
            jTable.getModel().addTableModelListener(new TableModelListener() {
                public void tableChanged(TableModelEvent e) {
                    int row = e.getFirstRow();
                    int column = e.getColumn();
                    TableModel model = (TableModel) e.getSource();
                    String columnName = model.getColumnName(column);
                    Object data = model.getValueAt(row, column);
                    editTable(row, column, columnName, data, false);
                }
            });
        }
        scrollPane.setAutoscrolls(true);
        scrollPane.setBounds(171, 13, 609, 317);
        contentPane.add(scrollPane);
        return true;
    }

    protected static void editTable(int row, int column, String columnName, Object data, boolean isChangeView) {
        Table tb = Database.getLoadedTable(Database.lastChosenTable);
        tb.setChangeData(isChangeView, row, column, data, columnName);
    }

    private void addNewDataRowToLastTable() {
        // XXX
        if (!"".equals(Database.lastChosenTable)) {
            Table tb = Database.getLoadedTable(Database.lastChosenTable);
            JComponent[] inputs = tb.getComponentsForGettingInput();
            if (inputs == null) {
                JOptionPane.showMessageDialog(null,
                        "Table has no any properties.\nPlease add property before add new data row.", "Message", 1);
                return;
            }
            int res = JOptionPane.showConfirmDialog(null, inputs, "Add new data row", JOptionPane.OK_CANCEL_OPTION);

            if (res == JOptionPane.OK_OPTION) {
                // add new data row
                if (tb.addDataRow(inputs)) {
                    JOptionPane.showMessageDialog(null, "Add new row success", "Message", 1);
                    initJTable(false, false);
                    MainFrame.currentDatabase.flagChangeData = true;
                    repaint();
                    return;
                }
                JOptionPane.showMessageDialog(null, "Add new row failed. Reference or primary key is conflicted!", "Message", 1);
            }
        }
    }

    public boolean addNewDataRow(String tableName, DataRow dr) {
        // XXX

        Table tb = Database.getLoadedTable(tableName);
        return tb.addDataRow(dr, true);

    }

    private void addNewPropertyToLastTable() {
        Property p = addNewProperty(null, null, null, 0, null, false, false);
        if (!"".equals(Database.lastChosenTable) && p != null) {
            currentDatabase.addNewPropertyToLastTable(p);
            initJTable(true, false);
            MainFrame.currentDatabase.flagChangeData = true;
            repaint();
        }
    }

    private static void initEditorCell() {
        colunmsWithComboBox = new Vector<Integer>();
        colunmsWithComboBox.add(1);
        Vector<String> types = new Vector<String>();
        types.add("char");
        types.add("int");
        values = new Vector<Vector<String>>();
        values.add(types);
    }

    public static String tempDatabase = null;

    private static int addNewDatabaseWithDialog(String oldName, boolean oldCheck) {
        JTextField name = new JTextField(oldName);
        JCheckBox isSwitch = new JCheckBox();
        isSwitch.setSelected(oldCheck);

        final JComponent[] inputs = new JComponent[]{new JLabel("Name:"), name,
                new JLabel("Switch to new database after created"), isSwitch};

        int resLV1 = JOptionPane.showConfirmDialog(null, inputs, "Create new database", JOptionPane.OK_CANCEL_OPTION);

        if (resLV1 == JOptionPane.OK_OPTION) {
            if (createNewDatabase(name.getText().toLowerCase())) {
                if (isSwitch.isSelected()) {
                    // show message
                    int resLV2 = JOptionPane.showConfirmDialog(null,
                            "Create new database success! Save your session before switch to?", "Confirm",
                            JOptionPane.YES_NO_OPTION);
                    if (resLV2 == JOptionPane.YES_OPTION) {
                        tempDatabase = name.getText().toLowerCase();
                        return 3;
                    }
                    return 2;
                } else {
                    JOptionPane.showMessageDialog(null, "Create new database success!");
                    return 1;
                }
            } else {
                int resLV3 = JOptionPane.showConfirmDialog(null, "The database name is invalid.\nCreate again?",
                        "Confirm", JOptionPane.YES_NO_OPTION);

                if (resLV3 == JOptionPane.YES_OPTION) {
                    return addNewDatabaseWithDialog(name.getText().toLowerCase(), isSwitch.isSelected());
                }
            }
        }
        return 0;
    }

    private static Property addNewProperty(Table table, String databaseName, String oldName, int oldType,
            String oldLength, boolean oldUnique, boolean oldNull) {
        boolean flagInvalid = false;
        JTextField name = new JTextField(oldName);
        Vector<String> types = new Vector<String>();
        types.add("char");
        types.add("int");
        JComboBox<String> type = new JComboBox<String>(types);
        type.setSelectedIndex(oldType);
        JTextField length = new JTextField(oldLength);
        JCheckBox isUnique = new JCheckBox();
        isUnique.setSelected(oldUnique);
        JCheckBox isNull = new JCheckBox();
        isNull.setSelected(oldNull);

        final JComponent[] inputs = new JComponent[]{new JLabel(Property.COLUMN_NAME), name,
                new JLabel(Property.COLUMN_TYPE), type, new JLabel(Property.COLUMN_LENGTH), length,
                new JLabel(Property.COLUMN_IS_PRIMARY), isUnique, new JLabel(Property.COLUMN_ALLOW_NULL), isNull,};

        int res = JOptionPane.showConfirmDialog(null, inputs, "Add new property", JOptionPane.OK_CANCEL_OPTION);

        if (res != JOptionPane.OK_OPTION) {
            return null;
        }

        Pattern pattern1 = Pattern.compile("[A-Z,a-z,&%$#@!()*^ ]");

        Matcher m = pattern1.matcher(length.getText());
        if (m.find()) {
            JOptionPane.showMessageDialog(null, "Please enter only numbers in LENGTH textfield!");
            flagInvalid = true;
        } else {
            if ("".equals(length.getText())) {
                JOptionPane.showMessageDialog(null, "Must fill a positive number in LENGTH textfield!");
                flagInvalid = true;
            } else if (Integer.parseInt(length.getText()) <= 0) {
                JOptionPane.showMessageDialog(null, "Please enter only numbers > 0 in LENGTH textfield!");
                flagInvalid = true;
            }
        }
        if (!flagInvalid && "".equals(name.getText())) {

            JOptionPane.showMessageDialog(null, "Must fill a string in NAME textfield!");
            flagInvalid = true;

        }

        if (!flagInvalid
                && isExistProperty(name.getText().toLowerCase(), Database.lastChosenTable,
                        currentDatabase.getName())) {
            JOptionPane.showMessageDialog(null, "This name of property has existed!");
            flagInvalid = true;
        }

        if (flagInvalid) {
            int result = JOptionPane.showConfirmDialog(null, "Do you want to add again?", "Confirm",
                    JOptionPane.YES_NO_OPTION);
            if (result == JOptionPane.YES_OPTION) {
                return addNewProperty(table, databaseName, name.getText().toLowerCase(), type.getSelectedIndex(),
                        length.getText(), isUnique.isSelected(), isNull.isSelected());

            }

            return null;

        }

        JOptionPane.showMessageDialog(null, "Add property success!\n(" + name.getText().toLowerCase() + ", "
                + type.getSelectedItem().toString() + ", " + length.getText() + ", " + isUnique.isSelected() + ", "
                + isNull.isSelected() + ")");

        return new Property(name.getText().toLowerCase(), type.getSelectedItem().toString(), Integer.parseInt(length
                .getText()), isUnique.isSelected(), isNull.isSelected());
    }

    public static boolean isExistProperty(String propertyName, String tableName, String databaseName) {
        for (Table tb : Database.tables) {
            if (tb.getName().equals(tableName) && tb.getDatabaseName().equals(databaseName)) {
                for (int i = 0; i < tb.getSizeProperties(); i++) {
                    if (tb.getProperty(i).getName().toLowerCase().equals(propertyName.toLowerCase())) {
                        return true;
                    }
                }
            }
        }

        return false;
    }

    public static boolean isExistDatabase(String databaseName) {
        Vector<String> databaseNames = XMLManagement.getVectorOfDatabaseNames();
        for (String n : databaseNames) {
            if (!"".equals(n)) {
                if (n.toLowerCase().equals(databaseName.toLowerCase())) {
                    return true;
                }
            }
        }

        return false;
    }

    public static boolean createNewDatabase(String databaseName) {
        if ("".equals(databaseName))
            return false;
        if (isExistDatabase(databaseName))
            return false;
        XMLManagement.addNewDatabase(databaseName);
        return true;
    }

    public static Vector<Object> getHierarchyTableName() {
        if ("".equals(currentDatabase.getName()))
            return null;
        Vector<Object> vectorData = new Vector<Object>();
        vectorData.add(currentDatabase.getName());

        for (int i = 0; i < currentDatabase.getSizeTables(); i++) {
            vectorData.add(currentDatabase.getTable(i).getName());
        }

        return vectorData;

    }

    protected void addNewRefToLastTable() {
        // show dialog choose table ref to
        Object[] tableNames = currentDatabase.getListOfLoadedNameTablesHaveProperty().toArray();
        String s = (String) JOptionPane.showInputDialog(null, "Reference to table:", "Reference to table",
                JOptionPane.PLAIN_MESSAGE, null, tableNames, "_default");
        // if s is valid
        // show dialog ref pro to pro
        if ("".equals(s) || s == null) {
            return;
        } else {
            // show dialog ref to ref
            Reference r = addNewReference(s.toLowerCase(), null, null, null);
            if (!"".equals(Database.lastChosenTable) && r != null) {
                currentDatabase.addNewRefToLastTable(r);
                JOptionPane.showMessageDialog(null, "Add reference success", "Message", 1);
                initJTable(true, false);
                MainFrame.currentDatabase.flagChangeData = true;
                repaint();
                return;
            }
            JOptionPane.showMessageDialog(null, "Add reference fail.", "Message", 1);
        }

    }

    // XXX
    private static Reference addNewReference(String nameTableRefTo, String oldName, String oldPro, String oldProRefTo) {
        Vector<String> nameOfToRef = Database.getLoadedTable(Database.lastChosenTable).getAllPropertiesName();
        Vector<String> nameOfRefTo = Database.getLoadedTable(nameTableRefTo).getAllPropertiesName();
        JTextField nameRef = new JTextField(oldName);
        JComboBox<String> proToRef = new JComboBox<String>(nameOfToRef);
        JComboBox<String> proRefTo = new JComboBox<String>(nameOfRefTo);

        JComponent[] refInputs = new JComponent[]{new JLabel("Reference name"), nameRef,
                new JLabel("Property to reference"), proToRef, new JLabel("Reference to ? in" + nameTableRefTo),
                proRefTo};

        int res = JOptionPane.showConfirmDialog(null, refInputs, "Add new reference", JOptionPane.OK_CANCEL_OPTION);

        if (res == JOptionPane.OK_OPTION) {
            if (!nameRef.getText().equals("")
                    && !currentDatabase.isExistNameOfReferenceInTable(nameRef.getText(),
                            Database.lastChosenTable)) {
                return new Reference(nameRef.getText().toLowerCase(), proToRef.getSelectedItem().toString()
                        .toLowerCase(), proRefTo.getSelectedItem().toString().toLowerCase(),
                        nameTableRefTo.toLowerCase());
            } else {
                int result = JOptionPane.showConfirmDialog(null,
                        "Name of reference is existing or invalid.\nDo you want to add again?", "Confirm",
                        JOptionPane.YES_NO_OPTION);
                if (result == JOptionPane.YES_OPTION) {
                    return addNewReference(nameTableRefTo.toLowerCase(), nameRef.getText().toLowerCase(), proToRef
                            .getSelectedItem().toString().toLowerCase(), proRefTo.getSelectedItem().toString()
                            .toLowerCase());
                }
            }

        }
        return null;
    }
    // //
}

class ConnectionThread extends Thread {
    public void run() {
        new ConnectionHelper().startListening();
    }
}